package org.fulmen.logger;

import org.fulmen.Level;
import org.fulmen.appender.Appender;

import static org.fulmen.Level.DEBUG;
import static org.fulmen.Level.ERROR;
import static org.fulmen.Level.FATAL;
import static org.fulmen.Level.INFO;
import static org.fulmen.Level.TRACE;
import static org.fulmen.Level.WARN;

public final class Logger
{
    private final Appender appender;
    private final Level loggerLevel;
    private ThreadLocal<StringBuilder> builder = new ThreadLocal<StringBuilder>()
    {
        @Override
        protected StringBuilder initialValue()
        {
            return new StringBuilder();
        }
    };

    // TODO config?  factory?
    public Logger(final Level loggerLevel, final Appender appender)
    {
        final Level appenderLevel = appender.getLevel();
        this.loggerLevel = (loggerLevel.allowLogOf(appenderLevel)) ? appenderLevel : loggerLevel;
        this.appender = appender;
    }

    public void trace(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, TRACE);
    }

    public void trace(final String logMessage)
    {
        log(logMessage, TRACE);
    }

    public void debug(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, DEBUG);
    }

    public void debug(final String logMessage)
    {
        log(logMessage, DEBUG);
    }

    public void info(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, INFO);
    }

    public void info(final String logMessage)
    {
        log(logMessage, INFO);
    }

    public void warn(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, WARN);
    }

    public void warn(final String logMessage)
    {
        log(logMessage, WARN);
    }

    public void error(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, ERROR);
    }

    public void error(final String logMessage)
    {
        log(logMessage, ERROR);
    }

    public void fatal(final LogMessageBuilder logMessageBuilder)
    {
        log(logMessageBuilder, FATAL);
    }

    public void fatal(final String logMessage)
    {
        log(logMessage, FATAL);
    }


    private void log(final LogMessageBuilder logMessageBuilder, final Level level)
    {
        if (loggerLevel.allowLogOf(level))
        {
            final StringBuilder builder = getStringBuilder();
            logMessageBuilder.build(builder);
            appender.append(builder);
            builder.setLength(0);
        }
        logMessageBuilder.reset();
    }

    private void log(final String logMessage, final Level level)
    {
        if (loggerLevel.allowLogOf(level))
        {
            appender.append(logMessage);
        }
    }

    private StringBuilder getStringBuilder()
    {
        return builder.get();
    }
}
